package org.mitoma.logger.server;

import java.io.IOException;
import java.util.UUID;
import java.util.logging.Logger;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.digest.DigestUtils;
import org.mitoma.logger.client.LoggerService;
import org.mitoma.logger.shared.AuthInfo;
import org.mitoma.logger.shared.AuthenticationException;
import org.mitoma.logger.shared.RegistrationException;
import org.mitoma.logger.shared.User;
import org.mitoma.logger.shared.UserSession;

import com.google.appengine.api.mail.MailService;
import com.google.appengine.api.mail.MailService.Message;
import com.google.appengine.api.mail.MailServiceFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyService;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class LoggerServiceImpl extends RemoteServiceServlet implements
    LoggerService {
  private static final Logger logger = Logger.getLogger(LoggerServiceImpl.class
                                         .getName());

  static {
    ObjectifyService.register(User.class);
    ObjectifyService.register(UserSession.class);
  }

  @Override
  public AuthInfo login(String email, String password)
      throws AuthenticationException {
    Objectify ofy = ObjectifyService.begin();
    User user = ofy.query(User.class).filter("email", email).get();
    String passwordHash = DigestUtils.shaHex(password);
    if (!user.getPasswordHash().equals(passwordHash)) {
      throw new AuthenticationException("ログインに失敗しました。");
    }
    UserSession session = createSession(ofy, user);
    HttpServletResponse resp = getThreadLocalResponse();
    resp.addCookie(new Cookie("userSession", session.getId()));
    return new AuthInfo(user, session);
  }

  @Override
  public void preRegister(String email, String password)
      throws AuthenticationException, RegistrationException {
    Objectify ofy = ObjectifyService.begin();
    User user = ofy.query(User.class).filter("email =", email).get();
    if (user != null) {
      throw new RegistrationException("既に登録されているメールアドレスです。");
    }
    User newUser = new User();
    newUser.setId(UUID.randomUUID().toString());
    newUser.setEmail(email);
    newUser.setPasswordHash(DigestUtils.shaHex(password));
    // TODO 仮登録メールを送るなどなど。
    ofy.put(newUser);

    MailService mailService = MailServiceFactory.getMailService();

    Message message = new Message("mutetheradio@gmail.com", email,
        "CycleLogger仮登録メール", "仮登録したよ。本登録は " + registerUrl(newUser));
    try {
      mailService.send(message);
    } catch (IOException e) {
      ofy.delete(newUser);
      throw new RegistrationException("仮登録メールの送信に失敗しました。", e);
    }

  }

  @Override
  public AuthInfo register(String userId) {
    Objectify ofy = ObjectifyService.begin();
    User user = ofy.find(User.class, userId);
    user.setPreRegistration(false);
    ofy.put(user);
    UserSession session = createSession(ofy, user);
    HttpServletResponse resp = getThreadLocalResponse();
    resp.addCookie(new Cookie("userSession", session.getId()));
    return new AuthInfo(user, session);
  }

  private String registerUrl(User user) {
    HttpServletRequest req = getThreadLocalRequest();
    String registerUrl = String.format("%s://%s/CycleLogger.html#r:%s",
        req.getScheme(), req.getServerName(), user.getId());
    System.out.println(registerUrl);
    logger.fine(registerUrl);
    return registerUrl;
  }

  private UserSession createSession(Objectify ofy, User user) {
    UserSession userSession = new UserSession();
    userSession.setId(UUID.randomUUID().toString());
    userSession.setUser(new Key<User>(User.class, user.getId()));
    ofy.put(userSession);
    return userSession;
  }

  @Override
  public AuthInfo isLoggedIn() throws AuthenticationException {
    HttpServletRequest req = getThreadLocalRequest();
    Cookie[] cookies = req.getCookies();
    if (cookies == null) {
      throw new AuthenticationException();
    }
    for (Cookie cookie : cookies) {
      if (!"userSession".equals(cookie.getName())) {
        continue;
      }
      Objectify ofy = ObjectifyService.begin();
      UserSession session = ofy.find(UserSession.class, cookie.getValue());
      User user = ofy.find(session.getUser());
      return new AuthInfo(user, session);
    }
    throw new AuthenticationException();
  }

}
